const globalPath = "C:/Users/Administrator/AppData/Roaming/npm/node_modules/";
const require_g = function(m) {
	return require(globalPath + m)
};

const http = require('http'); //http协议模块
const url = require('url'); //url解析模块
const fs = require("fs"); //文件系统模块
const path = require("path"); //路径解析模块
const querystring = require('querystring'); //查询字符串
const zlib = require('zlib'); //文件压缩为gzip

var httpServe = (function() {
	"use strict";

	return {
		//启动服务
		start: function() {
			var port = this.config.port;
			var ip = this.config.ip;

			//创建一个服务
			var httpServer = http.createServer(this.processRequest.bind(this));

			//在指定的端口监听服务
			httpServer.listen(port, function() {
				console.log("[HttpServer][Start]", "runing at http://" + ip + ":" + port + "/");
			});

			httpServer.on("error", function(error) {
				console.error(error);
			});
		},

		/**
		 * 请求处理
		 * @param request
		 * @param response
		 */
		processRequest: function(request, response) {
			var _this = this;

			response.setHeader("Access-Control-Allow-Origin", "*"); //解决跨域问题
			response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
			response.setHeader("Access-Control-Allow-Headers", "x-requested-with , Content-Type");

			var requestUrlParse = url.parse(request.url, true) //格式化请求信息

			var pathName = requestUrlParse.pathname; //请求路径
			pathName = decodeURI(pathName); //对请求的路径进行解码，防止中文乱码

			var pathData = requestUrlParse.query, //请求地址携参
				queryData = '', //data传参
				requestData = pathData; //所以参数

			var rootPath = _this.config.path;
			var filePath = path.join(rootPath, pathName); //获取资源文件的绝对路径

			var httpMethod = request.method; //请求方式

			request.on('data', function(chunk) { //二进制流一节一节的接受文件
				queryData += chunk;
			});

			request.on('end', function() { //文件接受完
				if(queryData != '') {
					queryData = unescape(queryData); //解码二进制流
					queryData = querystring.parse(queryData);
				} else {
					queryData = {}
				}
				requestData = Object.assign({}, requestData, queryData);
			});

			fs.stat(filePath, function(err, stat) {
				if(err) { //文件(夹)不存在
					if(request.headers['x-requested-with'] == 'XMLHttpRequest') { //ajax请求
						response.writeHead(200, {
							"Content-Type": "application/json"
						});
						var jsonText = JSON.stringify({
							"code": 404,
							"msg": "文件不存在"
						});
						response.end(jsonText);
					} else {
						var html = "<head><meta charset='utf-8'></head><div>文件不存在</div>";
						response.writeHead(404, {
							"Content-Type": "text/html"
						});
						response.end(html);

						//重定向
						/*response.writeHead(302, {
							'Location': 'index.html'
						});
						response.end();*/
					}

				} else { //如果文件(夹)名存在
					if(stat.isDirectory()) { //是文件夹
						var filedir = filePath.substring(filePath.lastIndexOf('\\') + 1); //用户访问的当前目录
						var files = fs.readdirSync(filePath); //获取用户访问路径下的文件列表
						if(filedir != '') filedir += '/';
						var html = "<!DOCTYPE html><head><meta charset='utf-8'></head>";
						//将访问路径下的所以文件一一列举出来，并添加超链接，以便用户进一步访问
						for(var i in files) {
							var filename = files[i];
							html += "<div><a  href='" + filedir + filename + "'>" + filename + "</a></div>";
						}
						response.writeHead(200, {
							"Content-Type": "text/html"
						});
						response.end(html);
					};

					if(stat.isFile()) { //是文件

						var fileContentType = _this.getContentType(filePath); //文件类型
						var acceptEncoding = request.headers['accept-encoding'];
						//gzip
						if(_this.config.gzip && acceptEncoding && acceptEncoding.indexOf('gzip') != -1 && fileContentType.indexOf('image/') == -1) { //浏览器支持zip(image没有压缩必要)
							response.setHeader("Content-Encoding", "gzip");
						}

						var lastModified = stat.mtime.toUTCString(); //获取文件修改时间
						var ifModifiedSince = request.headers['if-modified-since']; //传回Last-Modified后，再请求服务器会携带if-modified-since值来和服务器中的Last-Modified比较

						//304缓冲
						if(_this.config.cache) {
							var maxAgeTime = _this.config.cache; //超时时间
							if(ifModifiedSince && lastModified == ifModifiedSince) { //客户端修改时间和服务端修改时间对比
								response.writeHead(304, "Not Modified");
								response.end();

								return;
							} else {
								response.setHeader("Cache-Control", 'max-age=' + maxAgeTime + ', public'); //maxAgeTime秒后缓存失效
								//response.setHeader("Expires", "Mon, 07 Sep 2026 09:32:27 GMT");
								response.setHeader("Last-Modified", lastModified);
							}
						};

						response.writeHead(200, {
							"Content-Type": fileContentType + "; charset=utf-8", //获取对应文件的文档类型
						});

						var stream = fs.createReadStream(filePath, {
							flags: "r",
							encoding: null
						});

						stream.on("error", function() {
							response.writeHead(500, {
								"Content-Type": "text/html"
							});
							response.end("<h1>500 Server Error</h1>");
						});

						//gzip
						if(_this.config.gzip && acceptEncoding && acceptEncoding.indexOf('gzip') != -1 && fileContentType.indexOf('image/') == -1) { //浏览器支持zip(image没有压缩必要)
							var gzipStream = zlib.createGzip();
							stream.pipe(gzipStream).pipe(response); //返回文件流
						} else {
							stream.pipe(response); //返回文件流
						}

					}
				}
			});
		},

		/**
		 * 获取文档的内容类型
		 * @param filePath
		 * @returns {*}
		 */
		getContentType: function(filePath) {
			var contentType = this.config.mime;
			var ext = path.extname(filePath).substr(1);

			if(contentType.hasOwnProperty(ext)) {
				return contentType[ext] || 'text/html';
			} else {
				return contentType.default;
			}
		},

		///配置信息
		config: {
			port: 8082,
			path: '../',
			ip: '127.0.0.1',
			//cache: 60,
			//gzip: true,
			mime: {
				html: "text/html",
				js: "text/javascript",
				css: "text/css",
				gif: "image/gif",
				jpg: "image/jpeg",
				png: "image/png",
				svg: "image/svg+xml",
				ico: "image/icon",
				txt: "text/plain",
				json: "application/json",
				woff: "application/octet-stream",
				ttf: "application/octet-stream",
				eot: "application/octet-stream",
				map: "application/octet-stream",
				pdf: "application/pdf",
				xlsx: "application/octet-stream",
				default: "text/plain"
			}
		}
	}
})();

httpServe.start();